#页面父类
#主要封装一些每个UI都需要的通用的数据、通用的UI操作
#董哥的web自动化的神器。

import time,os,sys,autoit
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.select import Select
from selenium.webdriver.common.action_chains import ActionChains

class PageBase(object):
    def __init__(self,driver,base_url):
        self.driver=driver
        self.base_url=base_url

    #打开某url
    def open(self,PathUrl):
        self.driver.get(self.base_url+PathUrl)

    #根据元素的定位特征loc来定位到某元素
    def find_element(self,loc,isHightDisplay=False):
        by=loc[0]
        value=loc[1]
        ele=self.driver.find_element(by,value)
        if isHightDisplay:
            style = "background: green; border: 2px solid red;"
            self.driver.execute_script("arguments[0].setAttribute('style',arguments[1]);", ele, style)
        return ele

    def find_elements(self,loc):
        by=loc[0]
        value=loc[1]
        return self.driver.find_elements(by,value)

    # 适合控件：文本框、密码框、多行文本框
    #给某元素loc输入某数据data。追加模式
    def input(self,loc,data,isHightDisplay=False):
        self.find_element(loc,isHightDisplay).send_keys(data)

    # 对文本框/密码框/多行文本框进行清空并输入数据：不会触发鼠标失去焦点事件
    def clearAndInput(self, loc, data,isHightDisplay=False):
        ele = self.find_element(loc, isHightDisplay)
        ele.send_keys(Keys.CONTROL, 'a')#ctrl+A
        ele.send_keys(Keys.BACK_SPACE)
        ele.send_keys(data)

    # 清空文本框/密码框/多行文本框（会让鼠标失去焦点，触发前端的失去焦点）
    def clear(self, loc, isHightDisplay=False):
        self.find_element(loc, isHightDisplay).clear()

    #点击某元素loc
    def click(self,loc,isHightDisplay=False):
        self.find_element(loc,isHightDisplay).click()

    #获取某元素loc的文本内容（可自动去掉首尾空格）
    def getEleText(self,loc,isStrip=True):
        ele=self.find_element(loc)
        if isStrip:
            return ele.text.strip()
        else:
            return ele.text

    #获取某元素loc的某属性的值（可自动去掉首尾空格）
    def getEleAttr(self,loc,attrName,isStrip=True):
        ele=self.find_element(loc)
        if isStrip:
            return ele.get_attribute(attrName).strip()
        return ele.get_attribute(attrName)

    #判断某元素loc是否当前页面存在
    def isExists(self,loc):
        try:
            by=loc[0]
            value=loc[1]
            self.driver.find_element(by,value)
            return True
        except Exception:
            return False

    # 单选按钮控件：选中某选项
    def selectRaidoOption(self, attr_name, selectOptionValue):
        #<input type='radio' name='sex' value='M'>
        self.driver.find_element_by_css_selector(f"input[type='radio'][name='{attr_name}'][value='{selectOptionValue}']").click()

    # 复选框控件：选中0个/1个或N个选项。
    def selectCheckBoxOptions(self, attr_name, selectOptionsValues):#"" 或 "dalanqiu,tizuqiu" 或"dalanqiu"
        #<input type='checkbox' name='aihao' value='dalanqiu'>
        allOption = self.driver.find_elements_by_css_selector(f"input[type='checkbox'][name='{attr_name}']")
        for one in allOption:
            attr_value = one.get_attribute("value")
            selectStatus = one.is_selected()  # 获取该选项的原始选中状态
            if attr_value in selectOptionsValues:  # 该选项确保选中
                if not selectStatus:
                    one.click()
            else:  # 该选项确保不选中
                if selectStatus:
                    one.click()
    #复选框控件：全选
    def selectCheckBoxAllOptions(self,attrName):
        eles=self.driver.find_elements_by_css_selector(f"input[type='checkbox'][name='{attrName}']")
        for x in eles:
            if not x.is_selected():
                x.click()

    # 复选框控件：全不选
    def selectCheckBoxNoOptions(self, attrName):
        eles=self.driver.find_elements_by_css_selector(f"input[type='checkbox'][name='{attrName}']")
        for x in eles:
            if x.is_selected():
                x.click()

    # 复选框控件：反选
    def selectCheckReverseOptions(self, attrName):
        eles=self.driver.find_elements_by_css_selector(f"input[type='checkbox'][name='{attrName}']")
        for x in eles:
            x.click()

    # 下拉列表控件：选中某选项
    def selectSelectOption(self, attr_name,type="text",data=None):
        #<select name="degree">
        select = Select(self.driver.find_element_by_css_selector(f"select[name='{attr_name}']"))
        if type=="text":
            select.select_by_visible_text(data)  # 推荐
        elif type=="index":
            select.select_by_index(data)
        else:
            select.select_by_value(data)


    # 适合：日期控件
    # 输入某日期:直接输入：不通用
    def date_input1(self, loc, value,isReadOnly=False):
        ele = self.find_element(loc)
        if isReadOnly:
            self.driver.execute_script("arguments[0].removeAttribute('readonly')",ele)
        ele.send_keys(value)

    #适合：日期控件
    # 输入某日期:直接输入：通用
    def date_input2(self, loc, value, isReadOnly=False):
        ele = self.find_element(loc)
        if isReadOnly:
            self.driver.execute_script("arguments[0].removeAttribute('readonly')", ele)
        self.driver.execute_script("arguments[0].value=arguments[1]",ele,value)

    # 文件框：上传1个或N个文件/文件夹：实现方法1:不通用
    def uploadFiles1(self, loc_file, filePaths):#"" 或"C:/A/1.png" 或"C:/A/1.png,C:/A/2.png"
        if filePaths=="" or filePaths==None:
            return
        newFilePath=filePaths.replace(",","\n")
        ele=self.find_element(loc_file)
        ele.send_keys(newFilePath)

    # 文件框：上传1个或N个文件/文件夹：实现方式2：autoIT（通用版）
    def uploadFiles2(self, loc_file, filePaths):#"" 或"C:/A/1.png" 或"C:/A/1.png,C:/A/2.png"
        if filePaths=="" or filePaths==None:
            return

        # 实现步骤1
        ele = self.find_element(loc_file)
        ActionChains(self.driver).click(ele).perform()
        time.sleep(2)

        newFilePath = ""
        a = filePaths.split(",")  # a["C:/a/1.png","C:/A/2.png"]
        for x in a:  # "C:/A/1.png"
            newFilePath += '"' + x + '" '
        newFilePath = newFilePath.replace("/", "\\")

        autoit.win_wait("打开", 10)
        autoit.control_send("打开", "Edit1", newFilePath)
        autoit.control_click("打开", "Button1")

    # 处理JS三种弹出框
    # 获取三种JS弹出框的文本内容
    def getTextForJsTanCuKuan(self):
        return self.driver.switch_to.alert.text

    # 点击三种JS弹出框的“确定”按钮
    def acceptForJsTanCuKuan(self):
        self.driver.switch_to.alert.accept()

    # 点击三种JS弹出框的“取消”按钮
    def dismissForJsTanCuKuan(self):
        self.driver.switch_to.alert.dismiss()

    # 为JS的prompt弹出框输入文本
    def inputJsTanCuKuan(self, data):
        self.driver.switch_to.alert.send_keys(data)

    # iframe框架相关处理
    # 切换到某iframe
    def switch_iframe(self, type="loc",data=None):
        if type=="loc":
            ele=self.find_element(data)
            self.driver.switch_to.frame(ele)
        else:
            self.driver.switch_to.frame(data)


    # 切换到主iframe
    def switch_defaultIframe(self):
        self.driver.switch_to.default_content()

    # 鼠标操作的相关处理

    # 函数功能：鼠标单击某元素loc
    def mouse_click(self, loc, isHightDisplay=False):
        ele = self.find_element(loc, isHightDisplay)
        ActionChains(self.driver).click(ele).perform()

    # 函数功能：鼠标双击某元素loc
    def mouse_dbclick(self, loc, isHightDisplay=False):
        ele = self.find_element(loc, isHightDisplay)
        ActionChains(self.driver).double_click(ele).perform()

    # 函数功能：鼠标悬停在某元素loc
    def mouse_moveToEle(self, loc, isHightDisplay=False):
        ele = self.find_element(loc, isHightDisplay)
        ActionChains(self.driver).move_to_element(ele).perform()

    # 函数功能：滑动垂直滚动条到最底部
    def scrollToFloor(self):
        js1 = "window.scrollTo(0,10000)"
        self.driver.execute_script(js1)

    # 网页截图
    def savePng1(self, filePath):
        self.driver.get_screenshot_as_file(filePath)

    def savePng2(self, fileName):
        self.driver.get_screenshot_as_file("./screen/" + fileName + ".png")

    def savePng3(self, serviceName, key):
        fileName = serviceName + "_" + key + "_" + time.strftime("%Y%m%d%H%M%S")
        self.driver.get_screenshot_as_file("./screen/" + fileName + ".png")
        return fileName#"登录_K001_20250605100314"

    # 切换标签页/切换窗口:支持：下标切换、目标窗口的标题切换、目标窗口的url切换
    # 形参n是第几个窗口。n从0开始.-1：最新打开窗口
    def switch_windowByIndex(self, type="index",data="-1"):
        if type=="index":
            self.driver.switch_to.window(self.driver.window_handles[data])
        elif type=="title":
            moren_handler = self.driver.current_window_handle
            flag = True
            allWindows = self.driver.window_handles
            for one in allWindows:
                self.driver.switch_to.window(one)
                currentTitle = self.driver.title
                if data in currentTitle:
                    flag = False
                    break
                time.sleep(1)
            if flag:
                self.driver.switch_to.window(moren_handler)
        else:
            moren_handler = self.driver.current_window_handle
            flag = True
            allWindows = self.driver.window_handles
            for one in allWindows:
                self.driver.switch_to.window(one)
                currentUrl = self.driver.current_url
                if data in currentUrl:
                    flag = False
                    break
                time.sleep(1)
            if flag:
                self.driver.switch_to.window(moren_handler)

